//alarmtest.cc
//  Test the Alarm::GoToSleepFor(int wait) function.
//  If the thread sleeps for less than wait cycles the test is failed.

#include "copyright.h"
#include "system.h"
#include "alarm.h"
#include "interrupt.h"

//Toggle interrupts. Causes stats->totalTicks to increment.
static void
Toggle() {
    int i = 0;
    IntStatus oldLevel = interrupt->SetLevel(IntOn);
    for (i=0; i<500; i++) {
        interrupt->SetLevel(IntOff);
        interrupt->SetLevel(IntOn);
        currentThread->Yield();
    }
    interrupt->SetLevel(oldLevel);
}

//Calls Alarm::GoToSleepFor(...) and checks that it slept for at least the
//correct amount of time.
static void
alarm_thread(int which) {
    int start = stats->totalTicks;
    int diff = 0;

    Alarm::GoToSleepFor(which);

    diff = stats->totalTicks - start;

    //Print the results of the test.
    if(diff < which) {
        printf("\nERROR: Alarm::GoToSleepFor should have waited at least "
               "%d ticks, only waited %d ticks.\n", which, diff);
    } else {
        printf("%d:%d, ", diff, which);
    }
}

//Function called when the nachos executable is run.
//Creates a number of threads defined by alarm_thread above, and executes them.
//Then toggles interrupts repeatedly to increment the counter.
void
ThreadTest() {
    int num_threads = 20;
    char* thread_names[num_threads];
    Thread* threads[num_threads];

    DEBUG('t', "Running alarm test.");

    for(int i = 0; i < num_threads; i++) {
        //Note that this memory is never recovered.
        //It should be after a join on each thread, but
        //Thread doesn't support that (yet).
        DEBUG('t', "Thread %d", i);
        thread_names[i] = new char[10];
        sprintf(thread_names[i], "Alarm %d", i);
        threads[i] = new Thread(thread_names[i]);
        threads[i]->Fork(alarm_thread, i + 1);
    }

    Toggle();
}
